package com.wunong.smart.address.starter.repository;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.wunong.smart.address.client.query.UserAddressQueryDTO;
import com.wunong.smart.address.domain.UserAddressDomain;
import com.wunong.smart.address.repository.UserAddressRepository;
import com.wunong.smart.address.starter.infrastructure.mapper.UserAddressMapper;
import com.wunong.smart.address.starter.infrastructure.po.UserAddressPO;
import com.wunong.smart.domain.platform.utils.TimeUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

import static com.wunong.smart.address.starter.converter.UserAddressConverter.toDomain;
import static com.wunong.smart.address.starter.converter.UserAddressConverter.toPo;

/**
 * @author create by zealot.zt
 */
public class UserAddressRepositoryImpl implements UserAddressRepository {

    @Resource
    protected UserAddressMapper userAddressMapper;

    @Override
    public Long save(UserAddressDomain domain) {
        LocalDateTime now = TimeUtils.nowWithoutMs();
        domain.setGmtCreate(now);
        domain.setGmtModified(now);

        UserAddressPO po = toPo(domain);
        userAddressMapper.insert(po);
        domain.setId(po.getId());
        return po.getId();
    }

    @Override
    public void update(UserAddressDomain domain) {
        domain.setGmtModified(TimeUtils.nowWithoutMs());

        UserAddressPO po = toPo(domain);
        userAddressMapper.updateById(po);
    }

    @Override
    public UserAddressDomain getById(Long id) {
        Wrapper<UserAddressPO> wrapper = Wrappers.lambdaQuery(UserAddressPO.class)
                .eq(UserAddressPO::getId, id);

        return toDomain(userAddressMapper.selectOne(wrapper));
    }

    @Override
    public List<UserAddressDomain> queryByIds(Collection<Long> ids) {
        Wrapper<UserAddressPO> wrapper = Wrappers.lambdaQuery(UserAddressPO.class)
                .in(UserAddressPO::getId, ids);

        return toDomain(userAddressMapper.selectList(wrapper));
    }

    @Override
    public UserAddressDomain getById(Long userId, Long id) {
        Wrapper<UserAddressPO> wrapper = Wrappers.lambdaQuery(UserAddressPO.class)
                .eq(UserAddressPO::getUserId, userId)
                .eq(UserAddressPO::getId, id);

        return toDomain(userAddressMapper.selectOne(wrapper));
    }

    @Override
    public void resetDefaultFalse(UserAddressDomain domain) {
        Wrapper<UserAddressPO> wrapper = Wrappers.lambdaQuery(UserAddressPO.class)
                .eq(UserAddressPO::getUserId, domain.getUserId())
                .eq(UserAddressPO::getUserRole, domain.getUser().getRole())
                .ne(UserAddressPO::getId, domain.getId())
                .eq(UserAddressPO::getIsDefault, true);

        UserAddressDomain addressDomain = new UserAddressDomain();
        addressDomain.setGmtModified(TimeUtils.nowWithoutMs());
        addressDomain.setIsDefault(false);

        userAddressMapper.update(toPo(addressDomain), wrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void setDefault(UserAddressDomain domain) {
        // 重置原有用户地址
        resetDefaultFalse(domain);

        // 设为默认地址
        userAddressMapper.updateById(toPo(domain));
    }

    @Override
    public UserAddressDomain getByIdDefaultQueryFirst(Long userId, Long id) {
        UserAddressDomain domain = getById(userId, id);
        if (Objects.nonNull(domain) && domain.isValid()) {
            return domain;
        }

        LambdaQueryWrapper<UserAddressPO> wrapper = Wrappers.lambdaQuery(UserAddressPO.class)
                .eq(UserAddressPO::getUserId, userId)
                .orderByDesc(UserAddressPO::getGmtCreate);

        return toDomain(userAddressMapper.selectFirst(wrapper));
    }

    @Override
    public List<UserAddressDomain> queryByUser(Long userId, Integer userRole) {
        Wrapper<UserAddressPO> wrapper = Wrappers.lambdaQuery(UserAddressPO.class)
                .eq(UserAddressPO::getUserId, userId)
                .eq(UserAddressPO::getUserRole, userRole)
                .orderByDesc(UserAddressPO::getGmtCreate);

        return toDomain(userAddressMapper.selectList(wrapper));
    }

    @Override
    public List<UserAddressDomain> query(Long userId, UserAddressQueryDTO query) {
        LambdaQueryWrapper<UserAddressPO> wrapper = Wrappers.lambdaQuery(UserAddressPO.class)
                .eq(UserAddressPO::getUserId, userId)
                .orderByDesc(UserAddressPO::getGmtCreate);

        // 是否查询无效数据
        boolean includeInvalid = Boolean.TRUE.equals(query.getIncludeInvalid());
        if (!includeInvalid) {
            wrapper.eq(UserAddressPO::getValid, true);
        }

        if (StringUtils.isNotBlank(query.getMobile())) {
            wrapper.eq(UserAddressPO::getMobile, query.getMobile());
        }

        if (Objects.nonNull(query.getIsDefault())) {
            wrapper.eq(UserAddressPO::getIsDefault, query.getIsDefault());
        }

        if (Objects.nonNull(query.getId())) {
            wrapper.eq(UserAddressPO::getId, query.getId());
        }

        if (CollectionUtils.isNotEmpty(query.getIds())) {
            wrapper.in(UserAddressPO::getId, query.getIds());
        }

        return toDomain(userAddressMapper.selectList(wrapper));
    }

    @Override
    public UserAddressDomain getDefaultAddress(Long userId, Integer userRole) {
        LambdaQueryWrapper<UserAddressPO> wrapper = Wrappers.lambdaQuery(UserAddressPO.class)
                .eq(UserAddressPO::getUserId, userId)
                .eq(UserAddressPO::getUserRole, userRole)
                .eq(UserAddressPO::getIsDefault, true)
                .orderByDesc(UserAddressPO::getGmtCreate);

        return toDomain(userAddressMapper.selectFirst(wrapper));
    }

}
